package fuse.LaCollaFS.Metadades;

import java.util.Enumeration;
import java.util.Hashtable;

import java.util.List;

import org.jdom.Element;

import fuse.FuseFtype;
import fuse.FuseDirEnt;
import fuse.FuseStat;

public class Directori extends Estructura {

	private Hashtable<String, Estructura> Fills;

	private MetaDades dades;

	/**
	 * Constructor de la clase Directori Crea la taula de fills Crea el FuseStat
	 * amb valors per defecte
	 * 
	 * 
	 * @param path
	 *            Path complet del directori ( nom inclos)
	 * @param a
	 *            referencia a les metadades.
	 */
	public Directori(String path, MetaDades a) {

		this.defDir();
		this.setNom(path);
		FuseStat Estat = this.getStat();
		Estat = new FuseStat();

		Estat.atime = (int) (System.currentTimeMillis() / 1000L);

		Estat.ctime = (int) (int) (System.currentTimeMillis() / 1000L);
		;
		Estat.gid = 1000; // id del grup
	//	Estat.inode = 5; // inode??? ho podem usar per l'objecte de la colla?

		Estat.mode = FuseFtype.TYPE_DIR | 0755;

		Estat.mtime = (int) (System.currentTimeMillis() / 1000L);
		Estat.nlink = 1; // numero d'enllassos
		Estat.size = 4096; // tamany
		Estat.uid = 1000; // id usuari
		Estat.blocks = (int) ((Estat.size + 511L) / 512L);
		this.setStat(Estat);

		Fills = new Hashtable<String, Estructura>();

		dades = a;
	}

	/**
	 * Afegeix Estructura com a fill del directori
	 * 
	 * @param nom
	 *            Objecte a afegir penjant d'aquest directori
	 */
	public void AfegirFill(Estructura nom) {

		nom.setPare(this);
		String[] noms;
		noms = nom.getNom().split("@");

		Fills.put(noms[0], nom);

	}

	/**
	 * Elimina Fill del directori
	 * 
	 * @param nom
	 *            nom del fitxer/directori/enllaç a eliminar.
	 */
	public void EliminarFill(String nom) {

		Estructura a = this.BuscarFill(nom);
		Directori b;

		if (a.esDirectori()) {
			b = (Directori) a;
			if (b.Buit()) {
				// eliminar objecte a de LaColla.
				Fills.remove(a.getNom());
				a.delete();

			}

			else
				System.out.println("ERROR, DIRECTORI PLE!!!!!");
		} else {

			// Eliminar Fitxer de LaColla i l'object tb
			Fills.remove(a.getNom());
			Fitxer f;
			f = (Fitxer) a;
			f.Eliminar();
		}
	}

	public void EliminarFillRecursiu(String nom) {
		// p("he arribat fins aqui i busco " + nom);
		Estructura a = this.BuscarFill(nom);
		// p("nom del fill trobat : " + a.getNom() + " nom que hauria de ser : "
		// + nom);
		Fills.remove(a.getNom());

	}

	/**
	 * Busca recursiva entre els fills del directori en questió
	 * 
	 * @param path
	 *            path del fill que volem buscar
	 * @return retorna l'estructura trobada, null si no la troba
	 */
	public Estructura BuscarFill(String path) {

		Estructura node;
		node = this;

		if (node.getNom() == path) {

		} else {
			String[] pathParts = path.split("/");

			for (int i = 0; i < pathParts.length; i++) {
				String pathPart = pathParts[i];

				if (pathPart.equals("") || pathPart.equals(".")
						|| pathPart.equals(this.getNom())) {
					// estic en el mateix node
					node = this;

				} else if (pathPart.equals("..")) {
					// busco el node del pare.
					node = dades.ObtenirNode(this.getPare().ObtenirPath());

				} else if (node.esDirectori()) {
					// busco fill en el directori
					Directori d = (Directori) node;
					node = d.getFill(pathPart);

					if (node == null)
						break;
				}

			}
		}

		return (Estructura) node;
	}

	/**
	 * Recupera fill de la hashtable.
	 * 
	 * @param path2
	 *            fill a recuperar
	 * @return Estructura del fill recuperat.
	 */
	public Estructura getFill(String path2) {
		String[] paths;
		paths = path2.split("@");

		return Fills.get(paths[0]);
	}

	/**
	 * Llista tots els fills del directori
	 * 
	 * @return retorna array de FuseDirEnt ja omplert llest per retornar al FUSE
	 */
	public FuseDirEnt[] Llistarfills() {
		int numfills = Fills.size() + 2;

		FuseDirEnt[] dirEntries = new FuseDirEnt[numfills];

		Enumeration iter = Fills.elements();
		FuseDirEnt jomateix = new FuseDirEnt();
		FuseDirEnt elmeupare = new FuseDirEnt();

		// els valors de . i .. només es per que es llistin quan fas un ls -a
		// els valors reals els agafa el VFS del sistema de fitxers que toca
		dirEntries[0] = jomateix;
		dirEntries[1] = elmeupare;
		jomateix.name = ".";
		jomateix.mode = this.getStat().mode;
		jomateix.inode = 1;
		

		elmeupare.name = "..";
		elmeupare.mode = (this.getStat()).mode; // es indiferent...
		elmeupare.inode = 2;

		for (int i = 2; i < numfills; i++) {

			Estructura node = (Estructura) iter.nextElement();
			FuseDirEnt dirEntry = new FuseDirEnt();
			dirEntries[i] = dirEntry;
			if (node.esFitxer()) {
				Fitxer fit = (Fitxer) node;
				dirEntry.name = fit.getNom()+"@"+fit.getVersion();
			} else {
				dirEntry.name = node.getNom();
			}
			dirEntry.mode = node.getStat().mode;
		}
		p("direntries length" +dirEntries.length);
	
		return dirEntries;
	}

	/**
	 * Comprova si el directori té fills
	 * 
	 * @return retorna true si no te fills, false si té algun fill
	 */
	public boolean Buit() {

		return Fills.isEmpty();
	}

	/**
	 * Imprimeix per pantalla
	 * 
	 * @param o
	 */
	private void p(Object o) {

		System.out.println(o);
	}

	/**
	 * Crea Element XML de tot el directori i els seus fills
	 * 
	 * @return
	 */
	public Element CrearXML() {
		// p("creem el xml....");
		Element root = new Element("Directori");
		root.setAttribute("Nom", this.getNom());

		if (this.getPare() == null) {
			// p("node arrel, no te pare");
			root.setAttribute("Pare", "/media/");
		} else
			root.setAttribute("Pare", this.getPare().getNom());
		// p("mirem el fusestat....");
		Element estat = new Element("Stat");

		estat.setAttribute("atime", String.valueOf(this.getStat().atime));
		estat.setAttribute("blocks", String.valueOf(this.getStat().blocks));
		estat.setAttribute("ctime", String.valueOf(this.getStat().ctime));
		estat.setAttribute("gid", String.valueOf(this.getStat().gid));
//		estat.setAttribute("inode", String.valueOf(this.getStat().inode));
		estat.setAttribute("mode", String.valueOf(this.getStat().mode));
		estat.setAttribute("mtime", String.valueOf(this.getStat().mtime));
		estat.setAttribute("nlink", String.valueOf(this.getStat().nlink));
		estat.setAttribute("size", String.valueOf(this.getStat().size));
		estat.setAttribute("uid", String.valueOf(this.getStat().uid));
		root.addContent(estat);
		// p("mirem els fills....");
		Element fills = new Element("Fills");
		Enumeration iter = Fills.elements();
		for (int i = 0; i < Fills.size(); i++) {
			// System.out.println("#fill:"+Fills.size());
			Estructura node = (Estructura) iter.nextElement();

			Element fill;
			if (node.esDirectori()) {
				Directori direct = (Directori) node;
				fill = direct.CrearXML();
			} else if (node.esFitxer()) {
				// p("conte un fitxer");
				Fitxer fit = (Fitxer) node;
				fill = fit.CrearXML();
			} else {
				fill = new Element("Enllas");
			}
			fills.addContent(fill);

		}
		root.addContent(fills);
		return root;
	}

	/**
	 * Reconstrueix el Directori i els seus fills a partir de l'Element XML
	 * 
	 * @param root
	 */
	public void LlegirXML(Element root) {

		Element stat;
		Element fills;
		// p("directori type: " + root.getName());
		this.setNom(root.getAttributeValue("Nom"));
		// this.setPare(root.getAttributeValue("Pare"));
		List l = root.getChildren();
		stat = (Element) l.get(0);
		// p("Stat Type: " + stat.getName());

		FuseStat estat;
		estat = this.getStat();
		// omplir stat.....
		estat.atime = Integer.valueOf(stat.getAttributeValue("atime"))
				.intValue();
		estat.blocks = Integer.valueOf(stat.getAttributeValue("blocks"))
				.intValue();
		estat.ctime = Integer.valueOf(stat.getAttributeValue("ctime"))
				.intValue();
		estat.gid = Integer.valueOf(stat.getAttributeValue("gid")).intValue();
//		estat.inode = Integer.valueOf(stat.getAttributeValue("inode"))
	//			.intValue();
		estat.mode = Integer.valueOf(stat.getAttributeValue("mode")).intValue();
		estat.mtime = Integer.valueOf(stat.getAttributeValue("mtime"))
				.intValue();
		estat.nlink = Integer.valueOf(stat.getAttributeValue("nlink"))
				.intValue();
		estat.size = Integer.valueOf(stat.getAttributeValue("size")).intValue();
		estat.uid = Integer.valueOf(stat.getAttributeValue("uid")).intValue();
		this.setStat(estat);

		fills = (Element) l.get(1);

		List lfills = fills.getChildren();
		for (int i = 0; i < lfills.size(); i++) {
			Element node = (Element) lfills.get(i);
			if (node.getName() == "Directori") {

				Directori dir = new Directori(node.getAttributeValue("Nom"),
						dades);
				dir.LlegirXML(node);
				this.AfegirFill(dir);
			} else if (node.getName() == "Fitxer") {
				Fitxer fit = new Fitxer(node.getAttributeValue("Nom"), dades);
				fit.LlegirXML(node);
				// p("continc un fitxer de nom " +fit.getNom());
				this.AfegirFill(fit);
			} else if (node.getName() == "Enllas") {
				Enllas en = new Enllas(node.getAttributeValue("Nom"), dades);
				en.LlegirXML(node);
				this.AfegirFill(en);
			}

		}

	}



	

}
